package com.apes.fn.controlling.vehicle.service;

import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.fixedLoss.modle.LossQuotation;
import com.apes.fn.business.fixedLoss.repository.LossQuotationRepository;
import com.apes.fn.controlling.vehicle.model.VehicleInfo;
import com.apes.fn.controlling.vehicle.repository.VehicleInfoRepository;
import com.apes.fn.crm.customerExpand.FnCustomerExpand;
import com.apes.fn.server.pickUpCar.model.PickUpCar;
import com.apes.fn.server.pickUpCar.repository.PickUpCarRepository;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.model.ServicePlanItem;
import com.apes.fn.server.servicePlan.repository.ServicePlanItemRepository;
import com.apes.fn.server.servicePlan.repository.ServicePlanRepository;
import com.apes.fn.server.transferVehicle.model.InnerPickDeliveryUpCar;
import com.apes.fn.server.workOrder.model.ConstructionRecord;
import com.apes.fn.server.workOrder.model.MaintenanceOrder;
import com.apes.fn.server.workOrder.repository.ConstructRecordRepository;
import com.apes.fn.server.workOrder.repository.MaintenanceOrderRepository;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.express.FuncAlias;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.DistributedLock;
import com.apes.scm.masterdata.frame.model.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 车辆信息服务
 *
 * @author xul
 * @create 2020-12-23 15:23
 **/

@Service
public class VehicleInfoService extends abstractVehicleinfo{

    @Autowired
    private DistributedLock distributedLock;

    private final VehicleInfoRepository repository;
    private final OutboxEventService outboxEventService;

    public VehicleInfoService(VehicleInfoRepository repository, OutboxEventService outboxEventService) {
        this.repository = repository;
        this.outboxEventService = outboxEventService;
    }

    @OutboxSubscriber(name = "车辆服务信息：接车单")
    public void subscribePickUpCar(PickUpCar pickUpCar) {
        if (pickUpCar.getFnCustomerExpand() == null) return;
        createVehicleInfo(pickUpCar.getDept(), pickUpCar.getFnCustomerExpand());
    }

    @OutboxSubscriber(name = "车辆服务信息：服务方案", condition = " confirmDate != null ")
    public void subscribeServicePlan(ServicePlan servicePlan) {
        createVehicleInfo(servicePlan.getSaleDept(), servicePlan.getFnCustomerExpand());
    }

    @OutboxSubscriber(name = "车辆服务信息：定损报价 ")
    public void subscribeLossQuotation(LossQuotation lossQuotation) {
        innerPickDeliveryUpCar(lossQuotation.getFixedLossDept(), lossQuotation.getCustomerExpand());
    }

    @OutboxSubscriber(name = "车辆服务信息：接车单")
    public void subscribeInnerPickUpCar(InnerPickDeliveryUpCar pickUpCar) {
        innerPickDeliveryUpCar(pickUpCar.getBelongDept(), pickUpCar.getFnCustomerExpand());
    }

    private void innerPickDeliveryUpCar(Dept belongDept, FnCustomerExpand fnCustomerExpand) {
        VehicleInfo vehicleInfo = repository.findAll(JpaDsl.toCriteriaByEq("dept", belongDept, "fnCustomerExpand", fnCustomerExpand, "state", "start")).stream().findAny().orElse(null);
        if(vehicleInfo != null) outboxEventService.sendSaveEvent(vehicleInfo);
    }


    private void createVehicleInfo(Dept dept, FnCustomerExpand fnCustomerExpand) {
        String lockId = "vehicleInfo_" + fnCustomerExpand.getId();
        try {
            if (!distributedLock.lock(lockId, 5 * 1000)) {
                throw new RuntimeException("资源忙，等待自动执行");
            }
            VehicleInfo vehicleInfo = repository.findAll(JpaDsl.toCriteriaByEq("dept", dept, "fnCustomerExpand", fnCustomerExpand, "state", "start")).stream().findAny().orElse(null);
            if (vehicleInfo != null) {
//            outboxEventService.sendSaveEvent(vehicleInfo);
            } else {
                vehicleInfo = new VehicleInfo();
                vehicleInfo.setDept(dept);
                vehicleInfo.setFnCustomerExpand(fnCustomerExpand);
            }
            JSONObject planState = planStateForNew(obtainPlanData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId()));
            JSONObject carJson = obtainCarData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId());
            if(carJson != null){
                vehicleInfo.setPickUpCar(carJson.getString("ID"));
            }
            if(!carState(carJson) && !planState.getBoolean("haveConfirmToReci")
                    && !(existLossQuotation(vehicleInfo.getFnCustomerExpand().getId()))){
                vehicleInfo.setState("finish");
            }
//        vehicleInfo.setQTest(planState.getBoolean("haveQTest"));
            repository.saveAndFlush(vehicleInfo);
        }finally {
            distributedLock.unlock(lockId);
        }
    }



    @FuncAlias(name = "接车")
    public String funOnePickCar(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();
        boolean carState = carState(obtainCarData(deptId,fnId)); //接车状态
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(carState){
            if(planState.getBoolean("haveWaitWork")) return "B";  //存在有施工，优先级最高
            if(planState.getBoolean("haveWaitTest")) return "C"; //存在有质检，优先级第二
            if(planState.getBoolean("haveWaitMoney")) return "D"; //存在有收款，优先级第二
            return "A";  //待做方案，优先级最低
        }
        return "N";
    }

    @FuncAlias(name = "创建服务方案")
    public boolean funTwoCreatePlan(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        boolean carState = carState(obtainCarData(deptId,fnId)); //接车状态
        if(!carState && planState.getBoolean("haveWaitDoPlan")) return true;
        return false;
    }

    @FuncAlias(name = "确认服务方案")
    public boolean funThreeConfirmPlan(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(planState.getBoolean("haveConfirmPlan")) return true;
        return false;
    }

    @FuncAlias(name = "终止服务方案") //待施工状态触发（可能回到待出方案a，交车B，待出方案b，待施工 F，待总检查c，待结算d，待交车e）
    public String funFourClosePlan(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();

        boolean carState = carState(obtainCarData(deptId,fnId)); //接车状态

        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(planState.getBoolean("haveWaitWork")) return "F";
        if(planState.getBoolean("haveWaitTest") && !planState.getBoolean("haveWaitWork")) return "C";
        if(planState.getBoolean("haveWaitMoney") && !(planState.getBoolean("haveWaitWork") || planState.getBoolean("haveWaitTest") )) return "D";

        if(carState){ //车在店，可能到待出方案，待交车
            if(vehicleInfo.isQTest()){ //本次接车有到过质检的（但是无确认到收款单据），待交车
                return "E";
            }else{ //待做方案
                return "A";
            }
        }else{ //完成交车（接单交车）
            return "B";
        }
    }


    @FuncAlias(name = "解锁工单") //从待总检，待结算两个状态触发，发现有施工的，返回true
    public boolean funFiveUnlockPlan(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(planState.getBoolean("haveWaitWork") && planState.getBoolean("haveWaitWorkUnLock")) return true;
        return false;
    }

    @FuncAlias(name = "完成施工") //待施工状态触发
    public boolean funSixFinishPlan(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(!planState.getBoolean("haveWaitWork") && planState.getBoolean("haveWaitTest")) return true;
        return false;
    }

    @FuncAlias(name = "完成总检") //待总检状态触发
    public boolean funSevemFinishTest(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(!planState.getBoolean("haveWaitWork") && !planState.getBoolean("haveWaitTest") && planState.getBoolean("haveWaitMoney")) return true;
        return false;
    }

    @FuncAlias(name = "完成结算") //(到待交车状态 A ,到交车状态 B ,不变N)
    public String funEightFinishMoney(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        String fnId = vehicleInfo.getFnCustomerExpand().getId();
        String deptId = vehicleInfo.getDept().getId();

        boolean carState = carState(obtainCarData(deptId,fnId)); //接车状态
        JSONObject planState = planState(obtainPlanData(deptId,fnId));
        if(planState.getBoolean("haveConfirmToReci")){ //还存在单据，不变
            return "N";
        }else{
            if(carState){
                return "A";
            }else{
                return "B";
            }
        }
    }

    @FuncAlias(name = "完成交车") //在待交车节点才会触发（检索车是否在店即可）
    public boolean funNineBackCar(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        if(vehicleInfo.getPickUpCar() != null){
            PickUpCar pickUpCar = SpringManager.getBean(PickUpCarRepository.class).findOne(vehicleInfo.getPickUpCar());
            if(!"approve".equals(pickUpCar.getState())) return  true;
        }
        return false;
    }


    @FuncAlias(name = "有接车") //在待交车节点才会触发（检索车是否在店即可）
    public boolean isdHavePickCar(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        return carState(obtainCarData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId())); //接车状态
    }

    @FuncAlias(name = "未结单且无接车") //在待交车节点才会触发（检索车是否在店即可）
    public boolean isdNoCarNoRe(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        boolean carStart = carState(obtainCarData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId()));
        JSONObject planState = planState(obtainPlanData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId()));

        if(!carStart && planState.getBoolean("haveConfirmToReci")) return true;
        return false;
    }

    @FuncAlias(name = "结单且无接车") //在待交车节点才会触发（检索车是否在店即可）
    public boolean isdNoCarRe(String id){
        VehicleInfo vehicleInfo = repository.findOne(id);
        boolean carStart = carState(obtainCarData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId()));
        JSONObject planState = planState(obtainPlanData(vehicleInfo.getDept().getId(),vehicleInfo.getFnCustomerExpand().getId()));

        if(!carStart && !planState.getBoolean("haveConfirmToReci")) return true;
        return false;
    }
    public void testFun(SimpleRequest re){
        System.out.println(funOnePickCar(re.getJO().getString("id")));
        System.out.println(funTwoCreatePlan(re.getJO().getString("id")));
        System.out.println(funThreeConfirmPlan(re.getJO().getString("id")));
        System.out.println(funFourClosePlan(re.getJO().getString("id")));
        System.out.println(funFiveUnlockPlan(re.getJO().getString("id")));
        System.out.println(funSixFinishPlan(re.getJO().getString("id")));
        System.out.println(funSevemFinishTest(re.getJO().getString("id")));
        System.out.println(funEightFinishMoney(re.getJO().getString("id")));
        System.out.println(funNineBackCar(re.getJO().getString("id")));
    }


    @FuncAlias(name = "方案锁定状态") //方案是否锁定
    public boolean lockPlanState(String id){
        boolean re = false;
        try {
            ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(id);
            if(servicePlan != null){
                List<MaintenanceOrder> maintenanceOrders =
                        SpringManager.getBean(MaintenanceOrderRepository.class).findInnerMaintenanceOrder(servicePlan.getServicePlanItems().stream().map(servicePlanItem -> {
                            return servicePlanItem.getId();
                        }).collect(Collectors.toList()));
                List llist = maintenanceOrders.stream().filter(maintenanceOrder -> {
                    return maintenanceOrder.isLockState();
                }).collect(Collectors.toList());

                if(llist.size() != 0) return true;
            }
        }catch (Exception e){
            re = false;
        }
        return re;
    }
    @FuncAlias(name = "服务方案号") //根据工单号获取
    public String obtainPlanID(String id){
        List<ServicePlanItem> servicePlanItems = SpringManager.getBean(ServicePlanItemRepository.class).findPlanByModer(id);
        return servicePlanItems == null || servicePlanItems.size() == 0 ? "" : servicePlanItems.stream().findFirst().get().getServicePlan().getId();
    }

    @FuncAlias(name = "暂停施工原因") //根据工单号获取
    public String obtainReason(String id){
        List<ConstructionRecord> constructionRecords =
                SpringManager.getBean(ConstructRecordRepository.class).findAll(JpaDsl.toCriteria("maintenanceOrder.id","EQ",id,"operateType","EQ","pause"), PageRequest.of(0, 100)).getContent();
        return constructionRecords.stream().filter(constructionRecord -> {return constructionRecord.getOperateReason() != null;}).map(constructionRecord -> {return constructionRecord.getOperateReason().getDescription();}).collect(Collectors.joining(";","",""));
    }

    @FuncAlias(name = "获取方案服务类型") //根据方案号获取服务类型
    public String obtainServeTypeByS(String id){
        ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(id);
        if(servicePlan != null){
            List<MaintenanceOrder> maintenanceOrders =
                    SpringManager.getBean(MaintenanceOrderRepository.class).findInnerMaintenanceOrder(servicePlan.getServicePlanItems().stream().map(servicePlanItem -> {
                        return servicePlanItem.getId();
                    }).collect(Collectors.toList()));
            if(maintenanceOrders != null && maintenanceOrders.size() != 0) return maintenanceOrders.stream().map(maintenanceOrder -> {
                return maintenanceOrder.obtainWorkPlatForm();
            }).distinct().collect(Collectors.joining("、","",""));
        }
        return "";
    }
    @FuncAlias(name = "获取工单服务类型") //根据方案号获取服务类型
    public String obtainServeTypeByM(String id){
        MaintenanceOrder maintenanceOrder = SpringManager.getBean(MaintenanceOrderRepository.class).findOne(id);
        return maintenanceOrder.obtainWorkPlatForm();
    }

    /**
     * 判断是否存在定损单
     * @param customerExpand 会员扩展信息id
     */
    public boolean existLossQuotation(String customerExpand){
        List<LossQuotation> quotationList = SpringManager.getBean(LossQuotationRepository.class).findAll(
                JpaDsl.toCriteriaByEq("customerExpand.id", customerExpand)
        );
        if (quotationList.size() == 0){
            return false;
        }else {
            // anyMatch() 断言函数,肯定满足条件, 不满足返回false
            return quotationList.stream().anyMatch(item -> {
                return !Objects.equals("businessAudit", item.getState())
                        && !Objects.equals("repeal", item.getState()) ;
            });
        }
    }
}
